package main

import (
	"encoding/json"
	"log"
	"net/http"
	"time"

	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
)

func main() {
	gin.SetMode(gin.ReleaseMode)
	r := gin.Default()
	// r.SetTrustedProxies(nil)
	r.SetTrustedProxies([]string{"127.0.0.1"})

	// 配置 CORS
	r.Use(cors.New(cors.Config{
		AllowOrigins:     []string{"*"}, // 允许所有源
		AllowMethods:     []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
		AllowHeaders:     []string{"Origin", "Content-Type", "Accept"},
		ExposeHeaders:    []string{"Content-Length"},
		AllowCredentials: true,
		MaxAge:           12 * time.Hour,
	}))
	// 作用于全局
	r.Use(gin.Logger())
	r.Use(gin.Recovery())
	// 注册全局异常处理中间件
	r.Use(Recovery())

	// 作用于单个路由
	r.GET("/benchmark", MyBenchLogger(), benchEndpoint)

	// 作用于某个组
	authorized := r.Group("/")
	authorized.Use(AuthRequired())
	{
		authorized.POST("/login", loginEndpoint)
		authorized.POST("/submit", submitEndpoint)
	}

	r.GET("/", func(c *gin.Context) {
		c.String(200, "Hello, Geektutu")
	})
	// 匹配 /user/geektutu
	r.GET("/user/:name", func(c *gin.Context) {
		name := c.Param("name")
		c.String(http.StatusOK, "Hello %s", name)
	})
	// 匹配users?name=xxx&role=xxx，role可选
	r.GET("/users", func(c *gin.Context) {
		name := c.Query("name")
		role := c.DefaultQuery("role", "teacher")
		c.String(http.StatusOK, "%s is a %s", name, role)
	})
	// POST
	r.POST("/form", func(c *gin.Context) {
		username := c.PostForm("username")
		password := c.DefaultPostForm("password", "000000") // 可设置默认值
		c.JSON(http.StatusOK, gin.H{
			"username": username,
			"password": password,
		})
	})
	// POST
	r.POST("/form2", func(c *gin.Context) {
		var loginRequest LoginRequest
		if err := c.ShouldBindJSON(&loginRequest); err != nil {
			log.Panic("ShouldBindJSON error: ", err.Error())
		} else {
			log.Println("ShouldBindJSON success")
			log.Println(json.Marshal(loginRequest))
		}
		// 原始的body
		// body, _ := io.ReadAll(c.Request.Body)
		// fmt.Println(string(body))
		log.Println("------")
		c.JSON(http.StatusOK, gin.H{
			"username": loginRequest.Username,
			"password": loginRequest.Password,
		})
	})
	// GET 和 POST 混合
	r.POST("/posts", func(c *gin.Context) {
		id := c.Query("id")
		page := c.DefaultQuery("page", "0")
		username := c.PostForm("username")
		password := c.DefaultPostForm("username", "000000") // 可设置默认值

		c.JSON(http.StatusOK, gin.H{
			"id":       id,
			"page":     page,
			"username": username,
			"password": password,
		})
	})
	r.POST("/post", func(c *gin.Context) {
		ids := c.QueryMap("ids")
		names := c.PostFormMap("names")

		c.JSON(http.StatusOK, gin.H{
			"ids":   ids,
			"names": names,
		})
	})
	r.GET("/redirect", func(c *gin.Context) {
		c.Redirect(http.StatusMovedPermanently, "/index")
	})
	r.GET("/index", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"title": "index",
		})
	})
	r.GET("/goindex", func(c *gin.Context) {
		c.Request.URL.Path = "/"
		r.HandleContext(c)
	})

	r.POST("/upload1", func(c *gin.Context) {
		file, _ := c.FormFile("file")
		// c.SaveUploadedFile(file, dst)
		c.String(http.StatusOK, "%s uploaded!", file.Filename)
	})
	r.POST("/upload2", func(c *gin.Context) {
		// Multipart form
		form, _ := c.MultipartForm()
		files := form.File["upload[]"]

		for _, file := range files {
			log.Println(file.Filename)
			// c.SaveUploadedFile(file, dst)
		}
		c.String(http.StatusOK, "%d files uploaded!", len(files))
	})

	// Template
	r.LoadHTMLGlob("templates/*")
	stu1 := &student{Name: "Geektutu", Age: 20}
	stu2 := &student{Name: "Jack", Age: 22}
	r.GET("/arr", func(c *gin.Context) {
		c.HTML(http.StatusOK, "arr.tmpl", gin.H{
			"title":  "Gin",
			"stuArr": [2]*student{stu1, stu2},
		})
	})

	log.Println("Server is running on 127.0.0.1:8080")
	r.Run("127.0.0.1:8080") // listen and serve on 0.0.0.0:8080

	// 热加载调试 Hot Reload
	// github.com/codegangsta/gin
	// github.com/pilu/fresh
	// 下载 gin, 确认一下GOPATH, GOBIN, 执行需要将执行GOBIN/gin.exe 全路径执行
	// go install github.com/codegangsta/gin@latest
	// $env:PATH  = "$(go env GOBIN);" + $env:PATH
	// gin.exe -i -b 127.0.0.1:8080
	// go install github.com/gravityblast/fresh@latest
	// fresh.exe

}
func MyBenchLogger() gin.HandlerFunc {
	return func(c *gin.Context) {
		t := time.Now()
		// 请求前
		c.Next()
		// 请求后
		latency := time.Since(t)
		log.Printf("%s %s %s %s %s", c.Request.Method, c.Request.URL.Path, c.Request.Proto, c.Writer.Status(), latency)
	}
}

func benchEndpoint(c *gin.Context) {
	// 模拟一个耗时的操作
	time.Sleep(100 * time.Millisecond)
	c.String(http.StatusOK, "Hello, world!")
}

func loginEndpoint(c *gin.Context) {
	// 模拟一个耗时的操作
	time.Sleep(100 * time.Millisecond)
	c.JSON(http.StatusOK, gin.H{
		"message": "login success",
	})
}
func AuthRequired() gin.HandlerFunc {
	return func(c *gin.Context) {
		token := c.GetHeader("Authorization")
		if token != "xxxxx" {
			c.JSON(http.StatusUnauthorized, gin.H{
				"message": "unauthorized",
			})
			c.Abort()
		}
		c.Next()
	}
}

func submitEndpoint(c *gin.Context) {
	// 模拟一个耗时的操作
	time.Sleep(100 * time.Millisecond)
	c.JSON(http.StatusOK, gin.H{
		"message": "submit success",
	})
}

func Logger() gin.HandlerFunc {
	return func(c *gin.Context) {
		t := time.Now()
		// 给Context实例设置一个值
		c.Set("geektutu", "1111")
		// 请求前
		c.Next()
		// 请求后
		latency := time.Since(t)
		log.Print(latency)
	}
}

// 定义接收 JSON 的结构体
type LoginRequest struct {
	Username string `json:"username" binding:"required"`
	Password string `json:"password" binding:"required"`
}

type student struct {
	Name string
	Age  int8
}

// 统一响应格式
type Response struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data,omitempty"`
}

// 全局异常处理中间件
func Recovery() gin.HandlerFunc {
	return func(c *gin.Context) {
		defer func() {
			if err := recover(); err != nil {
				// 打印错误堆栈信息
				log.Printf("panic: %v", err)

				// 返回统一的 JSON 错误响应
				c.JSON(http.StatusInternalServerError, Response{
					Code:    500,
					Message: "服务器内部错误",
				})

				// 终止后续处理
				c.Abort()
			}
		}()
		c.Next() // 调用下一个中间件/handler
	}
}
